package models;

import play.*;
import play.db.jpa.*;

import javax.persistence.*;

import java.sql.SQLException;
import java.util.*;

import play.libs.Codec;
import java.util.*;

@Entity
public class RegisteredUser extends Model {
	/** Mohammed mattr */
	public String name;
	/** Mohammed mattr */
	public String mail;
	/** Mohammed mattr */
	public String password;
	/** Mohammed mattr */
	public String passwordHash;
	/** Nada El-sherief */
	public boolean isPrivate;
	/** Nada El-sherief */
	public boolean isPublic;
	public boolean isHousekeeper;
	public boolean isReviewer;

	/** Ayatullah Marawan */
	@OneToMany
	@JoinColumn(name = "privateListMapping")
	public List<RegisteredUser> privateList;
	/** Ayatullah Marawan */
	@ManyToOne(cascade = CascadeType.ALL)
	public RegisteredUser privateListOwner;

	/** Heidi ElToukhy */
	@OneToMany
	@JoinColumn(name = "publicListMapping")
	public List<RegisteredUser> publicList;
	/** Heidi ElToukhy */
	@ManyToOne(cascade = CascadeType.ALL)
	public RegisteredUser publicListOwner;

	public int points = 0;
	public ArrayList createdTutorials;
	/** mohammed mattr */
	public boolean isAdmin;
	public static boolean isCreator;
	public boolean isContributor;

	/** Nada El-sherief */
	@ManyToMany(mappedBy = "membersList", cascade = CascadeType.ALL)
	public List<CommunityList> CommunityLists;

	/** Ayatullah Marawan */
	@ManyToMany
	@JoinTable(name = "RequestsToAllUsersToJoin")
	public List<CommListRequests> requestsToJoinCommList;

	/** Ebaa */
	@OneToMany(mappedBy = "owner", cascade = CascadeType.ALL)
	public List<CommunityList> ownerCommunityLists;

	// Start --> Omnia
	@ManyToMany
	@JoinTable(name = "contributedTuts")
	public List<Tutorial> contributedTutorials;
	@OneToMany
	public List<Request> requestToContributeList;
	@ManyToMany
	@JoinTable(name = "likedTuts")
	public List<Tutorial> likeList;
	// @OneToMany (mappedBy ="receiver", cascade=CascadeType.ALL)
	// List<Notification> notificationList;
	// End -- >Omnia

	@ElementCollection
	public List<Integer> scores;

	@ManyToMany
	@JoinTable(name = "exercisetaken")
	public List<Exercise> exerciseTaken;

	/** Nada El-Sherief */
	@ManyToMany
	@JoinTable(name = "creatorRequests")
	public List<RequestOfCommListCreator> requestsToCreatorCommList;

	/** Ayatullah Marawan */
	@OneToMany(mappedBy = "creator", cascade = CascadeType.ALL)
	public List<CommunityList> createdCommLists;

	// start ...> Dana
	@ManyToMany
	@JoinTable(name = "tableOfReviewRequest")
	public List<ReviewRequest> listOfReviewRequest;

	// End -- > Dana

	/** Marwa Elshenawy */
	@ManyToMany
	@JoinTable(name = "followedTutorials")
	public List<Tutorial> followedTuts;

	/** Marwa Elshenawy */
	@ManyToMany
	@JoinTable(name = "followedTopics")
	public List<Topic> followedTops;

	/** Marwa Elshenawy */
	@ManyToMany
	@JoinTable(name = "FavoriteTutorials")
	public List<Tutorial> favoriteTuts;

	/** Marwa Elshenawy */
	@ManyToMany
	@JoinTable(name = "followedUsers")
	public List<RegisteredUser> followedUsrs;// People who are followed

	// --Start ---Rana A. Zakaria
	@ManyToMany
	@JoinTable(name = "ratedTutorials")
	public List<Tutorial> rateList;
	// End -- > Rana A. Zakaria

	// --Start ---Rana A. Zakaria
	@ManyToMany
	@JoinTable(name = "editRequests")
	public List<EditRequest> editRequest;

	// End -- > Rana A. Zakaria

	public RegisteredUser(String name, String mail, String password,
			boolean isAdmin) {
		this.name = name;
		this.mail = mail;
		this.password = password;
		this.points = 0;
		this.isAdmin = isAdmin;
		this.isCreator = false;
		this.isContributor = false;
		this.isReviewer = false;

		this.isHousekeeper = false;
		requestsToCreatorCommList = new ArrayList<RequestOfCommListCreator>();

		createdTutorials = new ArrayList();
		listOfReviewRequest = new ArrayList();

		createdCommLists = new ArrayList();
		ownerCommunityLists = new ArrayList();

		contributedTutorials = new ArrayList<Tutorial>();
		this.passwordHash = Codec.hexMD5(this.password);

		ownerCommunityLists = new ArrayList<CommunityList>();
		followedTuts = new ArrayList<Tutorial>();
		followedTops = new ArrayList<Topic>();
		favoriteTuts = new ArrayList<Tutorial>();
		followedUsrs = new ArrayList<RegisteredUser>();
		editRequest = new ArrayList<EditRequest>();
		likeList = new ArrayList<Tutorial>();
		this.save();

	}

	/**
	 * getter for RequestsToJoinCommList attribute
	 * 
	 * @author ayatullah Marwan
	 * @return List<CommListRequests>
	 */
	public List<CommListRequests> getRequestsToJoinCommList() {
		return requestsToJoinCommList;
	}

	/**
	 * setter for RequestsToJoinCommList attribute
	 * 
	 * @author ayatullah marawan
	 * @param List
	 *            <CommListRequests> requestsToJoinCommList
	 * 
	 */
	public void setRequestsToJoinCommList(
			List<CommListRequests> requestsToJoinCommList) {
		this.requestsToJoinCommList = requestsToJoinCommList;
	}

	/**
	 * This method checks if exists or not
	 * 
	 * @author mohammed
	 */
	public static boolean isExist(String mail) {
		return (count("mail=? ", mail) == 1);
	}

	/**
	 * This method checks if the user entered right data or not
	 * 
	 * @author mohammed
	 */
	public static boolean isValidLogin(String email, String password) {
		return (count("mail=? AND PasswordHash=?", email,
				Codec.hexMD5(password)) == 1);
	}

	/**
	 * This method connects the user if he is valid
	 * 
	 * @author mohammed
	 */

	public static RegisteredUser connect(String email, String password) {
		return RegisteredUser.find("mail= ? AND PasswordHash= ?", email,
				Codec.hexMD5(password)).first();
	}

	// Rana Amr
	// this method takes the id of the tutorial that has just been created, and
	// adds it to the
	// createTutorials list of the user.
	public void addTutorial(long TutorialID) {
		createdTutorials.add(TutorialID);
	}

	/***
	 * @author dana This method changes the variable of isReviewer
	 * @param isReviewer
	 */
	public void setReviewer(boolean isReviewer) {
		this.isReviewer = isReviewer;
	}

	// start @ author Nada
	// this method sets and saves the reviewer to true and returns it
	// to be used in the method checkMypoints
	// end @ author Nada
	public boolean isReviewer() {
		isReviewer = true;
		this.save();
		return isReviewer;

	}

	// start @ author Nada
	// this method returns the reviewer status, true or false.
	// end @ author Nada
	public boolean getReviewer() {
		return isReviewer;
	}

	public static boolean isCreator() {
		if (isCreator == true) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * This method takes the user id and checks if the user is admin or not
	 * returns true if user is admin or false if not
	 * 
	 * @author mohammed mattr
	 * @param userId
	 *            the id of the user
	 */

	public static boolean isAdmin(long userId) {

		RegisteredUser u = RegisteredUser.findById(userId);
		if (u.isAdmin) {
			return true;
		}
		return false;

	}

	public static boolean isReviewer(long userId) {

		RegisteredUser u = RegisteredUser.findById(userId);
		if (u.isReviewer) {
			return true;
		}
		return false;

	}

	/**
	 * setter for isAdmint attribute
	 * 
	 * @author mohamed mattr
	 * @param boolean isAdmin isAdmin the boolean attribute that checks if the
	 *        user is admin or not
	 * 
	 */
	public void setAdmin(boolean isAdmin) {
		this.isAdmin = isAdmin;
	}

	public boolean isHousekeeper() {
		return isHousekeeper;
	}

	public void setHousekeeper(boolean isHousekeeper) {
		this.isHousekeeper = isHousekeeper;
	}

	public String getName() {
		return name;
	}

	/**
	 * setter for name attribute
	 * 
	 * @author aya MArwan
	 * @param String
	 *            name
	 * 
	 */
	public void setName(String name) {
		this.name = name;
	}

	// start @ author Nada
	// this method returns the number of points
	// end @ author Nada
	public int getPoints() {
		return points;

	}

	// start @ author Nada
	// this method add points to the already gained points.
	// this method is called in createTutorial and ReviewTutorial and creating
	// exercises
	// end @ author Nada
	public int addPoints() {
		points = points + 5;
		this.save();
		return points;
	}

	public void updateLikeList(Tutorial t) {
		this.likeList.add(t);
		this.save();
	}

	public void updatecontributedTutorialsList(Tutorial t) {
		this.contributedTutorials.add(t);
	}

	// Begin ----> Ebaa
	/**
	 * getter for contributedTutorials attribute
	 * 
	 * @author Ebaa
	 * @return List<Tutorial>
	 */
	public List<Tutorial> getContributedTutorials() {
		return contributedTutorials;
	}

	/**
	 * setter for contributedTutorials attribute
	 * 
	 * @author Ebaa
	 * @param contributedTutorials
	 *            list of contributed tutorials of a user
	 */
	public void setContributedTutorials(List<Tutorial> contributedTutorials) {
		this.contributedTutorials = contributedTutorials;
	}

	/**
	 * getter for isContributor attribute
	 * 
	 * @author Ebaa
	 * @return boolean
	 */
	public boolean isContributor() {
		return isContributor;
	}

	/**
	 * setter for contributedTutorials attribute
	 * 
	 * @author Ebaa
	 * @param isContributor
	 *            boolean is contributor
	 */
	public void setContributor(boolean isContributor) {
		this.isContributor = isContributor;
	}

	/**
	 * getter for ownerCommunityLists attribute
	 * 
	 * @author Ebaa
	 * @return List<CommunityList>
	 */
	public List<CommunityList> getOwnerCommunityLists() {
		return ownerCommunityLists;
	}

	/**
	 * setter for contributedTutorials attribute
	 * 
	 * @author Ebaa
	 * @param ownerCommunityLists
	 *            list of owned community lists of the user
	 */
	public void setOwnerCommunityLists(List<CommunityList> ownerCommunityLists) {
		this.ownerCommunityLists = ownerCommunityLists;
	}

	/**
	 * getter for createdCommLists attribute
	 * 
	 * @author Ebaa
	 * 
	 * @return List<CommunityList>
	 */
	public List<CommunityList> getCreatedCommLists() {
		return createdCommLists;
	}

	/**
	 * setter for createdCommLists attribute
	 * 
	 * @author Ebaa
	 * @param createdCommLists
	 *            list of created community lists of the user
	 */
	public void setCreatedCommLists(List<CommunityList> createdCommLists) {
		this.createdCommLists = createdCommLists;
	}

	/**
	 * getter for communityLists attribute
	 * 
	 * @author Ebaa
	 * 
	 * @return List<CommunityList>
	 */
	public List<CommunityList> getCommunityLists() {
		return CommunityLists;
	}

	/**
	 * setter for communityLists attribute
	 * 
	 * @author Ebaa
	 * @param communityLists
	 *            list of community lists that the user is member in
	 */
	public void setCommunityLists(List<CommunityList> communityLists) {
		CommunityLists = communityLists;
	}

	// End ----> Ebaa
	/***
	 * @author dana This method returns the list of registeredUsers in a list
	 * @return
	 */
	public static List<RegisteredUser> findUsers() {

		return RegisteredUser.findAll();
	}

	/***
	 * @author dana This method returns the list of reviewrequests
	 * @return
	 */
	public List<ReviewRequest> listOfReviewRequest() {

		return this.listOfReviewRequest;
	}

	public List<Request> getRequestToContributeList() {
		return this.requestToContributeList;
	}

	/**
	 * This method takes the uID and fID and return a true if the followed User
	 * is not in the list of followedUsers, and false if not
	 * 
	 * @param uID
	 *            which is the id of the current user.
	 * @param fID
	 *            which is the id of the followed User.
	 * @return boolean true or false
	 * 
	 * @author Marwa
	 */
	public boolean followUser(long uID, long fID) {
		RegisteredUser fu = RegisteredUser.findById(fID);
		RegisteredUser user = RegisteredUser.findById(uID);
		if (!(user.followedUsrs.contains(fu))) {
			user.followedUsrs.add(fu);
			fu.save();
			user.save();
			return true;
		} else {
			return false;
		}
	}

	/**
	 * the method gets the list of the followed topics
	 * 
	 * @author Nada
	 * @param uID
	 *            represents the RegisteredUserId user
	 * @return List of followed topics
	 */
	public List viewFollowedTopics(long uID) {
		RegisteredUser user = RegisteredUser.findById(uID);
		List<Topic> followedTopics = user.followedTops;
		return followedTopics;
	}

	/**
	 * the method gets the list of the followed tutorials
	 * 
	 * @author Nada
	 * @param uID
	 *            represents the RegisteredUserId user
	 * @return List of followed topics
	 */

	public List viewFollowedTutorials(long uID) {
		RegisteredUser user = RegisteredUser.findById(uID);
		List<Tutorial> followedTutorials = user.followedTuts;
		return followedTutorials;
	}

	/**
	 * the method gets the list of the followed users
	 * 
	 * @author Nada
	 * @param uID
	 *            represents the RegisteredUserId user
	 * @return List of followed topics
	 */

	public List viewFollowedUsers(long uID) {
		RegisteredUser user = RegisteredUser.findById(uID);
		List<RegisteredUser> followedUsers = user.followedUsrs;
		return followedUsers;
	}

	/**
	 * This method takes the uID and return the list of favorites of this User
	 * 
	 * @param uID
	 *            which is the id of the current user.
	 * @return List of favorites of the current user
	 * 
	 * @author Marwa
	 */
	public List viewFavoriteTutorials(long uID) {
		RegisteredUser user = RegisteredUser.findById(uID);
		List<Tutorial> favoritesTutorials = user.favoriteTuts;
		return favoritesTutorials;
	}

	/**
	 * getter for RequestsToCreatorCommList attribute
	 * 
	 * @author Nada el sherif
	 * 
	 * @return List<RequestOfCommListCreator>
	 */
	public List<RequestOfCommListCreator> getRequestsToCreatorCommList() {
		return requestsToCreatorCommList;
	}

	public void setRequestsToCreatorCommList(
			List<RequestOfCommListCreator> requestsToCreatorCommList) {
		this.requestsToCreatorCommList = requestsToCreatorCommList;
	}

	/**
	 * getter for isPrivate attribute
	 * 
	 * @author Nada el sherif
	 * 
	 * @return boolean
	 */
	public boolean isPrivate() {
		return isPrivate;
	}

	/**
	 * setter for isPrivate attribute
	 * 
	 * @author nada el sherif
	 * @param boolean isPrivate
	 * 
	 */
	public void setPrivate(boolean isPrivate) {
		this.isPrivate = isPrivate;
		this.save();
	}

	/**
	 * getter for isPublic attribute
	 * 
	 * @author Nada el sherif
	 * 
	 * @return boolean
	 */
	public boolean isPublic() {
		return isPublic;
	}

	/**
	 * setter for isPublic attribute
	 * 
	 * @author nada el sherif
	 * @param boolean isPublic
	 * 
	 */
	public void setPublic(boolean isPublic) {
		this.isPublic = isPublic;
		this.save();
	}

	public List<Integer> getScores() {
		return scores;
	}

	public void setScores(List<Integer> scores) {
		this.scores = scores;
	}

	public List<Exercise> getExerciseTaken() {
		return exerciseTaken;
	}

	public void setExerciseTaken(List<Exercise> exerciseTaken) {
		this.exerciseTaken = exerciseTaken;
	}
}
// end @ author Nada

